package wsepForum.persistance;

import java.text.SimpleDateFormat;
import java.util.*;

import org.compass.core.*;
import org.compass.core.config.CompassConfiguration;

import wsepForum.common.elements.*;
import wsepForum.logging.ForumLogger;
import wsepForum.logging.ForumLogger.LoggerCategory;

public class CompassSearchAdaptor implements ISearchAdaptor {

	private static Compass compass;

	private static CompassSearchAdaptor INSTANCE = null;

	private CompassSearchAdaptor(boolean test) {
		CompassConfiguration config = new CompassConfiguration();
		if(test) {
			config.setConnection("searchTest");
		} else {
			config.setConnection("searchData");
		}
		config.addClass(Message.class);
		compass = config.buildCompass();
	}

	public static synchronized ISearchAdaptor getInstance(boolean test) {
		if(INSTANCE == null) {
			ForumLogger.getInstance().info("Starting Compass...", LoggerCategory.PERSISTANCE);
			INSTANCE = new CompassSearchAdaptor(test);
		}
		return INSTANCE;
	}

	public static synchronized ISearchAdaptor getInstance() {
		return getInstance(false);
	}


	public void add(Message message) {
		CompassIndexSession indexSession = compass.openIndexSession();
		try {
			indexSession.save(message);
			indexSession.commit();
		} catch (CompassException e) {
			indexSession.rollback();
		} finally {
			indexSession.close();
		}
	}

	private void remove(int id) {
		CompassIndexSession indexSession = compass.openIndexSession();
		try {
			indexSession.delete(Message.class, id);
			indexSession.commit();
		} catch (CompassException e) {
			indexSession.rollback();
		} finally {
			indexSession.close();
		}
	}

	public void remove(Message message) {
		remove(message.getElementID());
	}

	public void clearDB() {
		ForumLogger.getInstance().info("Clearing Compass DB...", LoggerCategory.PERSISTANCE);
		compass.getSearchEngineIndexManager().deleteIndex();
		compass.getSearchEngineIndexManager().verifyIndex();
	}

	public void close() {
		ForumLogger.getInstance().info("Stopping Compass...", LoggerCategory.PERSISTANCE);
		compass.close();
	}

	public Vector<SearchResult> searchByAuthor(String authorName) throws Exception {
		String searchExpression = "author:" + "\"" + authorName + "\"";

		return search(searchExpression);

	}

	public Vector<SearchResult> searchByDate(Date from, Date to) throws Exception {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String searchExpression = "date:[" + dateFormat.format(from) + " TO " + dateFormat.format(to) + "]";

		return search(searchExpression);

	}


	public Vector<SearchResult> searchByContent(String sentence) throws Exception {

		Vector<String> query = splitSentence(sentence);

		String searchExpression = "contents:" + "\"" + query.get(0) + "\"";
		for(int i=1; i<query.size(); i++){
			searchExpression = searchExpression + " AND " + "\"" + query.get(i) + "\"";
		}

		return search(searchExpression);

	}

	private Vector<String> splitSentence(String sentence) {
		String[] phrases = sentence.split("\\s+");
		Vector<String> result = new Vector<String>();
		for(int i=0; i<phrases.length; i++){
			if(phrases[i].startsWith("\"", 0)){
				String phrase = phrases[i].substring(1);
				i++;
				while(i<phrases.length && !phrases[i].endsWith("\"")){
					phrase = phrase + " " + phrases[i];
					i++;
				}
				if(i<phrases.length){
					phrase = phrase + " " + phrases[i].substring(0, phrases[i].length() - 1);
				}
				result.add(phrase);
			} else {
				result.add(phrases[i]);
			}
		}

		return result;
	}


	private Vector<SearchResult> search(String searchExpression) throws Exception {
		CompassSearchSession session = compass.openSearchSession();
		CompassHits hits = session.find(searchExpression);
		Iterator<CompassHit> iterator = hits.iterator();

		Vector<SearchResult> result = new Vector<SearchResult>();

		while(iterator.hasNext()) {
			CompassHit hit = iterator.next();
			result.add(new SearchResult(Integer.parseInt(hit.getResource().getId()), hit.getScore()));
		}
		session.close();

		return result;
	}

}
